"""
动作组编辑器
用于编辑和管理六足机器人的动作组
"""

import json
import time
import threading
from typing import Dict, List, Optional, Tuple
from dataclasses import dataclass
from ..control import MotionController


@dataclass
class ActionStep:
    """动作步骤"""

    type: str  # 'servo', 'delay', 'composite', 'loop', 'condition', 'parallel'
    servo_id: Optional[int] = None
    position: Optional[int] = None
    speed: Optional[int] = None
    duration: Optional[float] = None  # 延迟时间（秒）
    sub_steps: Optional[List["ActionStep"]] = None  # 复合动作的子步骤
    loop_count: Optional[int] = None  # 循环次数
    loop_steps: Optional[List["ActionStep"]] = None  # 循环动作的子步骤
    condition: Optional[str] = None  # 条件表达式
    true_steps: Optional[List["ActionStep"]] = None  # 条件为真时的步骤
    false_steps: Optional[List["ActionStep"]] = None  # 条件为假时的步骤
    parallel_steps: Optional[List["ActionStep"]] = None  # 并行动作的步骤


class ActionGroup:
    """动作组"""

    def __init__(self, name: str):
        self.name = name
        self.steps: List[ActionStep] = []
        self.description: str = ""
        self.version: int = 1  # 版本号
        self.history: List[Dict] = []  # 版本历史
        self._save_version()  # 保存初始版本

    def _save_version(self) -> None:
        """保存当前版本到历史记录"""
        self.history.append(
            {
                "version": self.version,
                "steps": [
                    {
                        "type": step.type,
                        "servo_id": step.servo_id,
                        "position": step.position,
                        "speed": step.speed,
                        "duration": step.duration,
                    }
                    for step in self.steps
                ],
                "description": self.description,
                "timestamp": time.time(),
            }
        )

    def add_step(self, step: ActionStep) -> None:
        """添加动作步骤"""
        self.steps.append(step)
        self.version += 1
        self._save_version()

    def insert_step(self, index: int, step: ActionStep) -> None:
        """插入动作步骤"""
        self.steps.insert(index, step)
        self.version += 1
        self._save_version()

    def remove_step(self, index: int) -> None:
        """删除动作步骤"""
        if 0 <= index < len(self.steps):
            self.steps.pop(index)
            self.version += 1
            self._save_version()

    def move_step(self, from_index: int, to_index: int) -> None:
        """移动动作步骤"""
        if 0 <= from_index < len(self.steps) and 0 <= to_index < len(self.steps):
            step = self.steps.pop(from_index)
            self.steps.insert(to_index, step)
            self.version += 1
            self._save_version()

    def revert_to_version(self, version: int) -> bool:
        """恢复到指定版本"""
        for history in reversed(self.history):
            if history["version"] == version:
                self.steps = [
                    ActionStep(
                        type=step["type"],
                        servo_id=step.get("servo_id"),
                        position=step.get("position"),
                        speed=step.get("speed"),
                        duration=step.get("duration"),
                    )
                    for step in history["steps"]
                ]
                self.description = history["description"]
                self.version = version
                return True
        return False

    def get_version_history(self) -> List[Dict]:
        """获取版本历史"""
        return self.history

    def to_dict(self) -> Dict:
        """转换为字典"""
        return {
            "name": self.name,
            "description": self.description,
            "steps": [
                {
                    "type": step.type,
                    "servo_id": step.servo_id,
                    "position": step.position,
                    "speed": step.speed,
                    "duration": step.duration,
                }
                for step in self.steps
            ],
        }

    @classmethod
    def from_dict(cls, data: Dict) -> "ActionGroup":
        """从字典创建"""
        group = cls(data["name"])
        group.description = data.get("description", "")
        group.steps = [
            ActionStep(
                type=step["type"],
                servo_id=step.get("servo_id"),
                position=step.get("position"),
                speed=step.get("speed"),
                duration=step.get("duration"),
            )
            for step in data["steps"]
        ]
        return group

    def copy(self) -> "ActionGroup":
        """创建动作组的副本"""
        new_group = ActionGroup(f"{self.name}_副本")
        new_group.description = self.description
        new_group.steps = [
            ActionStep(
                type=step.type,
                servo_id=step.servo_id,
                position=step.position,
                speed=step.speed,
                duration=step.duration,
            )
            for step in self.steps
        ]
        return new_group

    def merge(self, other: "ActionGroup") -> None:
        """合并另一个动作组"""
        self.steps.extend(other.steps)


class ActionEditor:
    """动作组编辑器"""

    def __init__(self, motion_controller: MotionController):
        """
        初始化动作组编辑器

        Args:
            motion_controller: 运动控制器实例
        """
        self.motion_controller = motion_controller
        self.current_group: Optional[ActionGroup] = None
        self.groups: Dict[str, ActionGroup] = {}
        self.templates: Dict[str, ActionGroup] = {}
        self._load_templates()

    def _load_templates(self) -> None:
        """加载模板"""
        # 基本姿态模板
        stand_template = ActionGroup("立正")
        stand_template.description = "立正姿态"
        stand_template.steps = [
            ActionStep(type="servo", servo_id=1, position=500, speed=100),
            ActionStep(type="servo", servo_id=2, position=500, speed=100),
            ActionStep(type="servo", servo_id=3, position=500, speed=100),
            ActionStep(type="servo", servo_id=4, position=500, speed=100),
            ActionStep(type="servo", servo_id=5, position=500, speed=100),
            ActionStep(type="servo", servo_id=6, position=500, speed=100),
        ]
        self.templates["立正"] = stand_template

        # 前进模板
        walk_forward_template = ActionGroup("前进")
        walk_forward_template.description = "前进动作"
        walk_forward_template.steps = [
            ActionStep(type="servo", servo_id=1, position=600, speed=100),
            ActionStep(type="servo", servo_id=2, position=400, speed=100),
            ActionStep(type="delay", duration=0.5),
            ActionStep(type="servo", servo_id=1, position=500, speed=100),
            ActionStep(type="servo", servo_id=2, position=500, speed=100),
        ]
        self.templates["前进"] = walk_forward_template

        # 后退模板
        walk_backward_template = ActionGroup("后退")
        walk_backward_template.description = "后退动作"
        walk_backward_template.steps = [
            ActionStep(type="servo", servo_id=1, position=400, speed=100),
            ActionStep(type="servo", servo_id=2, position=600, speed=100),
            ActionStep(type="delay", duration=0.5),
            ActionStep(type="servo", servo_id=1, position=500, speed=100),
            ActionStep(type="servo", servo_id=2, position=500, speed=100),
        ]
        self.templates["后退"] = walk_backward_template

    def create_group(self, name: str) -> ActionGroup:
        """创建新的动作组"""
        if name in self.groups:
            raise ValueError(f"动作组 '{name}' 已存在")

        group = ActionGroup(name)
        self.groups[name] = group
        self.current_group = group
        return group

    def load_group(self, name: str) -> ActionGroup:
        """加载动作组"""
        if name not in self.groups:
            raise ValueError(f"动作组 '{name}' 不存在")

        self.current_group = self.groups[name]
        return self.current_group

    def save_group(self, name: Optional[str] = None) -> None:
        """保存动作组"""
        if not self.current_group:
            raise ValueError("没有当前动作组")

        if name:
            self.current_group.name = name

        self.groups[self.current_group.name] = self.current_group

    def delete_group(self, name: str) -> None:
        """删除动作组"""
        if name not in self.groups:
            raise ValueError(f"动作组 '{name}' 不存在")

        del self.groups[name]
        if self.current_group and self.current_group.name == name:
            self.current_group = None

    def copy_group(self, name: str, new_name: Optional[str] = None) -> ActionGroup:
        """复制动作组"""
        if name not in self.groups:
            raise ValueError(f"动作组 '{name}' 不存在")

        source_group = self.groups[name]
        new_group = source_group.copy()

        if new_name:
            new_group.name = new_name

        self.groups[new_group.name] = new_group
        return new_group

    def merge_groups(self, target_name: str, source_name: str) -> None:
        """合并两个动作组"""
        if target_name not in self.groups:
            raise ValueError(f"目标动作组 '{target_name}' 不存在")
        if source_name not in self.groups:
            raise ValueError(f"源动作组 '{source_name}' 不存在")

        target_group = self.groups[target_name]
        source_group = self.groups[source_name]

        target_group.merge(source_group)

    def add_servo_step(self, servo_id: int, position: int, speed: int) -> None:
        """添加舵机动作步骤"""
        if not self.current_group:
            raise ValueError("没有当前动作组")

        step = ActionStep(
            type="servo", servo_id=servo_id, position=position, speed=speed
        )
        self.current_group.add_step(step)

    def add_delay_step(self, duration: float) -> None:
        """添加延迟步骤"""
        if not self.current_group:
            raise ValueError("没有当前动作组")

        step = ActionStep(type="delay", duration=duration)
        self.current_group.add_step(step)

    def add_composite_step(self, sub_steps: List[ActionStep]) -> None:
        """添加复合动作步骤"""
        if not self.current_group:
            raise ValueError("没有当前动作组")

        step = ActionStep(type="composite", sub_steps=sub_steps)
        self.current_group.add_step(step)

    def add_loop_step(self, loop_count: int, loop_steps: List[ActionStep]) -> None:
        """添加循环动作步骤"""
        if not self.current_group:
            raise ValueError("没有当前动作组")

        step = ActionStep(type="loop", loop_count=loop_count, loop_steps=loop_steps)
        self.current_group.add_step(step)

    def add_condition_step(
        self,
        condition: str,
        true_steps: List[ActionStep],
        false_steps: Optional[List[ActionStep]] = None,
    ) -> None:
        """添加条件动作步骤"""
        if not self.current_group:
            raise ValueError("没有当前动作组")

        step = ActionStep(
            type="condition",
            condition=condition,
            true_steps=true_steps,
            false_steps=false_steps,
        )
        self.current_group.add_step(step)

    def add_parallel_step(self, parallel_steps: List[ActionStep]) -> None:
        """添加并行动作步骤"""
        if not self.current_group:
            raise ValueError("没有当前动作组")

        step = ActionStep(type="parallel", parallel_steps=parallel_steps)
        self.current_group.add_step(step)

    def preview(self) -> None:
        """预览当前动作组"""
        if not self.current_group:
            raise ValueError("没有当前动作组")

        for step in self.current_group.steps:
            if step.type == "servo":
                self.motion_controller.move_servo(
                    step.servo_id, step.position, step.speed
                )
            elif step.type == "delay":
                time.sleep(step.duration)
            elif step.type == "composite":
                for sub_step in step.sub_steps:
                    if sub_step.type == "servo":
                        self.motion_controller.move_servo(
                            sub_step.servo_id, sub_step.position, sub_step.speed
                        )
                    elif sub_step.type == "delay":
                        time.sleep(sub_step.duration)
            elif step.type == "loop":
                for _ in range(step.loop_count):
                    for loop_step in step.loop_steps:
                        if loop_step.type == "servo":
                            self.motion_controller.move_servo(
                                loop_step.servo_id, loop_step.position, loop_step.speed
                            )
                        elif loop_step.type == "delay":
                            time.sleep(loop_step.duration)
            elif step.type == "condition":
                # 评估条件
                condition_result = eval(step.condition)
                steps_to_execute = (
                    step.true_steps if condition_result else step.false_steps
                )
                if steps_to_execute:
                    for condition_step in steps_to_execute:
                        if condition_step.type == "servo":
                            self.motion_controller.move_servo(
                                condition_step.servo_id,
                                condition_step.position,
                                condition_step.speed,
                            )
                        elif condition_step.type == "delay":
                            time.sleep(condition_step.duration)
            elif step.type == "parallel":
                # 创建线程执行并行动作
                threads = []
                for parallel_step in step.parallel_steps:
                    if parallel_step.type == "servo":
                        thread = threading.Thread(
                            target=self.motion_controller.move_servo,
                            args=(
                                parallel_step.servo_id,
                                parallel_step.position,
                                parallel_step.speed,
                            ),
                        )
                        threads.append(thread)
                        thread.start()
                    elif parallel_step.type == "delay":
                        time.sleep(parallel_step.duration)
                # 等待所有线程完成
                for thread in threads:
                    thread.join()

    def export_json(self, filename: str) -> None:
        """导出为JSON格式"""
        if not self.current_group:
            raise ValueError("没有当前动作组")

        with open(filename, "w", encoding="utf-8") as f:
            json.dump(self.current_group.to_dict(), f, indent=2, ensure_ascii=False)

    def import_json(self, filename: str) -> ActionGroup:
        """从JSON导入"""
        with open(filename, "r", encoding="utf-8") as f:
            data = json.load(f)

        group = ActionGroup.from_dict(data)
        self.groups[group.name] = group
        self.current_group = group
        return group

    def validate_group(self, name: str) -> Tuple[bool, List[str]]:
        """验证动作组"""
        if name not in self.groups:
            return False, [f"动作组 '{name}' 不存在"]

        group = self.groups[name]
        errors = []

        # 检查动作组是否为空
        if not group.steps:
            errors.append("动作组为空")

        # 检查每个步骤
        for i, step in enumerate(group.steps):
            if step.type == "servo":
                # 检查舵机参数
                if step.servo_id is None:
                    errors.append(f"步骤 {i+1}: 舵机ID未设置")
                if step.position is None:
                    errors.append(f"步骤 {i+1}: 舵机位置未设置")
                if step.speed is None:
                    errors.append(f"步骤 {i+1}: 舵机速度未设置")
            elif step.type == "delay":
                # 检查延迟参数
                if step.duration is None or step.duration <= 0:
                    errors.append(f"步骤 {i+1}: 延迟时间无效")
            elif step.type == "composite":
                # 检查复合动作
                if not step.sub_steps:
                    errors.append(f"步骤 {i+1}: 复合动作没有子步骤")
                else:
                    for j, sub_step in enumerate(step.sub_steps):
                        if sub_step.type == "servo":
                            if sub_step.servo_id is None:
                                errors.append(
                                    f"步骤 {i+1} 的子步骤 {j+1}: 舵机ID未设置"
                                )
                            if sub_step.position is None:
                                errors.append(
                                    f"步骤 {i+1} 的子步骤 {j+1}: 舵机位置未设置"
                                )
                            if sub_step.speed is None:
                                errors.append(
                                    f"步骤 {i+1} 的子步骤 {j+1}: 舵机速度未设置"
                                )
                        elif sub_step.type == "delay":
                            if sub_step.duration is None or sub_step.duration <= 0:
                                errors.append(
                                    f"步骤 {i+1} 的子步骤 {j+1}: 延迟时间无效"
                                )
            elif step.type == "loop":
                # 检查循环动作
                if step.loop_count is None or step.loop_count <= 0:
                    errors.append(f"步骤 {i+1}: 循环次数无效")
                if not step.loop_steps:
                    errors.append(f"步骤 {i+1}: 循环动作没有子步骤")
                else:
                    for j, loop_step in enumerate(step.loop_steps):
                        if loop_step.type == "servo":
                            if loop_step.servo_id is None:
                                errors.append(
                                    f"步骤 {i+1} 的循环步骤 {j+1}: 舵机ID未设置"
                                )
                            if loop_step.position is None:
                                errors.append(
                                    f"步骤 {i+1} 的循环步骤 {j+1}: 舵机位置未设置"
                                )
                            if loop_step.speed is None:
                                errors.append(
                                    f"步骤 {i+1} 的循环步骤 {j+1}: 舵机速度未设置"
                                )
                        elif loop_step.type == "delay":
                            if loop_step.duration is None or loop_step.duration <= 0:
                                errors.append(
                                    f"步骤 {i+1} 的循环步骤 {j+1}: 延迟时间无效"
                                )
            elif step.type == "condition":
                # 检查条件动作
                if not step.condition:
                    errors.append(f"步骤 {i+1}: 条件未设置")
                if not step.true_steps:
                    errors.append(f"步骤 {i+1}: 条件为真时的步骤未设置")
                else:
                    for j, true_step in enumerate(step.true_steps):
                        if true_step.type == "servo":
                            if true_step.servo_id is None:
                                errors.append(
                                    f"步骤 {i+1} 的条件为真步骤 {j+1}: 舵机ID未设置"
                                )
                            if true_step.position is None:
                                errors.append(
                                    f"步骤 {i+1} 的条件为真步骤 {j+1}: 舵机位置未设置"
                                )
                            if true_step.speed is None:
                                errors.append(
                                    f"步骤 {i+1} 的条件为真步骤 {j+1}: 舵机速度未设置"
                                )
                        elif true_step.type == "delay":
                            if true_step.duration is None or true_step.duration <= 0:
                                errors.append(
                                    f"步骤 {i+1} 的条件为真步骤 {j+1}: 延迟时间无效"
                                )
                if step.false_steps:
                    for j, false_step in enumerate(step.false_steps):
                        if false_step.type == "servo":
                            if false_step.servo_id is None:
                                errors.append(
                                    f"步骤 {i+1} 的条件为假步骤 {j+1}: 舵机ID未设置"
                                )
                            if false_step.position is None:
                                errors.append(
                                    f"步骤 {i+1} 的条件为假步骤 {j+1}: 舵机位置未设置"
                                )
                            if false_step.speed is None:
                                errors.append(
                                    f"步骤 {i+1} 的条件为假步骤 {j+1}: 舵机速度未设置"
                                )
                        elif false_step.type == "delay":
                            if false_step.duration is None or false_step.duration <= 0:
                                errors.append(
                                    f"步骤 {i+1} 的条件为假步骤 {j+1}: 延迟时间无效"
                                )
            elif step.type == "parallel":
                # 检查并行动作
                if not step.parallel_steps:
                    errors.append(f"步骤 {i+1}: 并行动作没有步骤")
                else:
                    for j, parallel_step in enumerate(step.parallel_steps):
                        if parallel_step.type == "servo":
                            if parallel_step.servo_id is None:
                                errors.append(
                                    f"步骤 {i+1} 的并行步骤 {j+1}: 舵机ID未设置"
                                )
                            if parallel_step.position is None:
                                errors.append(
                                    f"步骤 {i+1} 的并行步骤 {j+1}: 舵机位置未设置"
                                )
                            if parallel_step.speed is None:
                                errors.append(
                                    f"步骤 {i+1} 的并行步骤 {j+1}: 舵机速度未设置"
                                )
                        elif parallel_step.type == "delay":
                            if (
                                parallel_step.duration is None
                                or parallel_step.duration <= 0
                            ):
                                errors.append(
                                    f"步骤 {i+1} 的并行步骤 {j+1}: 延迟时间无效"
                                )
            else:
                errors.append(f"步骤 {i+1}: 未知的动作类型 '{step.type}'")

        return len(errors) == 0, errors

    def create_from_template(self, template_name: str, new_name: str) -> ActionGroup:
        """从模板创建动作组"""
        if template_name not in self.templates:
            raise ValueError(f"模板 '{template_name}' 不存在")

        if new_name in self.groups:
            raise ValueError(f"动作组 '{new_name}' 已存在")

        template = self.templates[template_name]
        new_group = template.copy()
        new_group.name = new_name
        self.groups[new_name] = new_group
        self.current_group = new_group
        return new_group

    def get_template_names(self) -> List[str]:
        """获取所有模板名称"""
        return list(self.templates.keys())

    def get_template(self, name: str) -> Optional[ActionGroup]:
        """获取指定模板"""
        return self.templates.get(name)

    def add_template(self, name: str, group: ActionGroup) -> None:
        """添加模板"""
        if name in self.templates:
            raise ValueError(f"模板 '{name}' 已存在")

        template = group.copy()
        template.name = name
        self.templates[name] = template

    def remove_template(self, name: str) -> None:
        """删除模板"""
        if name not in self.templates:
            raise ValueError(f"模板 '{name}' 不存在")

        del self.templates[name]
